﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using OthelloGame;

namespace OthelloCognition
{
    public class MinmaxSolver : AbstractSolver
    {
        private AbstractHeuristic h;

        public MinmaxSolver(Heuristics heur)
        {
            h = HeuristicFactory.getHeuricstic(heur);
        }

        public override SolverEnum SolverName()
        {
            return SolverEnum.Scoremax;
        }

        protected override void examineBoard(OthelloGameBoard current)
        {
            for (int i = 1; i < 61; i++)
            {
                move = DLMiniMax(current, i);
            }
        }

        private OthelloBoardLocation DLMiniMax(OthelloGameBoard board, int l)
        {
            if (board.AvailableOptionLocations.Count == 0) return null;
            int v = int.MinValue;
            List<OthelloBoardLocation> loc = new List<OthelloBoardLocation>();
            //OthelloBoardLocation loc = null;
            foreach (OthelloBoardLocation pit in board.AvailableOptionLocations)
            {
                OthelloGameBoard b = expandState(board, pit);
                int k = (int)(b.PlayersTurn != board.PlayersTurn ? MinVal(b, l - 1) : MaxVal(b, l - 1));
                if (k >= v)
                {
                    if (k > v)
                    {
                        v = k;
                        loc.Clear();
                    }
                    loc.Add(pit);
                }
            }
            Random r = new Random();

            int n = r.Next() % loc.Count;
            return loc.ElementAt(n);
        }

        private int MinVal(OthelloGameBoard board, int l)
        {
            if (l == 0 || board.AvailableOptionLocations.Count == 0) return h.evaluate(board, currentPlayer);
            int v = int.MaxValue;
            foreach (OthelloBoardLocation pit in board.AvailableOptionLocations)
            {
                OthelloGameBoard b = expandState(board, pit);
                v = Math.Min(v, b.PlayersTurn != board.PlayersTurn ? MaxVal(b, l - 1) : MinVal(b, l - 1));
            }
            return v;
        }

        private int MaxVal(OthelloGameBoard board, int l)
        {
            if (l == 0 || board.AvailableOptionLocations.Count == 0) return h.evaluate(board, currentPlayer);
            int v = int.MinValue;
            foreach (OthelloBoardLocation pit in board.AvailableOptionLocations)
            {
                OthelloGameBoard b = expandState(board, pit);
                v = Math.Max(v, b.PlayersTurn != board.PlayersTurn ? MinVal(b, l - 1) : MaxVal(b, l - 1));
            }
            return v;
        }
    }

    public class AlphaBetaSolver : AbstractSolver
    {
        AbstractHeuristic h;

        public AlphaBetaSolver(Heuristics heur)
        {
            h = HeuristicFactory.getHeuricstic(heur);
        }

        public override SolverEnum SolverName()
        {
            return SolverEnum.StabAB;
        }

        protected override void examineBoard(OthelloGameBoard current)
        {
            for (int i = 1; i < 61; i++)
            {
                move = AlphaBeta(current, i, int.MinValue, int.MaxValue);
            }
        }

        private OthelloBoardLocation AlphaBeta(OthelloGameBoard board, int l, int alpha, int beta)
        {
            if (board.AvailableOptionLocations.Count == 0) return null;
            int v = int.MinValue;
            OthelloBoardLocation loc = null;
            foreach (OthelloBoardLocation pit in board.AvailableOptionLocations)
            {
                OthelloGameBoard b = expandState(board, pit);
                int k = (int)(b.PlayersTurn != board.PlayersTurn ? MinVal(b, l - 1, alpha, beta) : MaxVal(b, l - 1, alpha, beta));
                if (k > v)
                {
                    v = k;
                    loc = pit;
                }
                alpha = Math.Max(alpha, v);
            }
            return loc;
        }

        private int MinVal(OthelloGameBoard board, int l, int alpha, int beta)
        {
            if (l == 0 || board.AvailableOptionLocations.Count == 0) return h.evaluate(board, currentPlayer);
            int v = int.MaxValue;
            foreach (OthelloBoardLocation pit in board.AvailableOptionLocations)
            {
                OthelloGameBoard b = expandState(board, pit);
                v = Math.Min(v, b.PlayersTurn != board.PlayersTurn ? MaxVal(b, l - 1, alpha, beta) : MinVal(b, l - 1, alpha, beta));
                if (v <= alpha) return v;
                beta = Math.Min(beta, v);
            }
            return v;
        }

        private int MaxVal(OthelloGameBoard board, int l, int alpha, int beta)
        {
            if (l == 0 || board.AvailableOptionLocations.Count == 0) return h.evaluate(board, currentPlayer);
            int v = int.MinValue;
            foreach (OthelloBoardLocation pit in board.AvailableOptionLocations)
            {
                OthelloGameBoard b = expandState(board, pit);
                v = Math.Max(v, b.PlayersTurn != board.PlayersTurn ? MinVal(b, l - 1, alpha, beta) : MaxVal(b, l - 1, alpha, beta));
                if (v >= beta) return v;
                alpha = Math.Max(alpha, v);
            }
            return v;
        }
    }
}